import Event from "da-event";
import $ipcConstants, { IpcMessage, CompressTask } from "./ipc.constant";
import $helper from "../helper.service";
import { Observable, of } from "rxjs";
import useSettingStore from "@renderer/store/useSettingStore";
import useAppStore from "@renderer/store/useAppStore";

export const ipcRenderer = window.electron.ipcRenderer



class IpcService extends Event {
  callbackSet = {}
  cacheFileSet: {[prop: string]: File} = {}
  bootstrap() {
    this.registerIpcEvents()
    this.getSystemDownloadDir()
  }
  registerIpcEvents() {
    ipcRenderer.on($ipcConstants.ipcMessageId, (_event: any, data: any) => this.handleIpcMessage(data))
  }

  handleIpcMessage(event: IpcMessage) {
    const {methodName, data, uuid} = event
    console.log(`handleIpcMessage---${methodName}`, event)
    if (typeof this.callbackSet[uuid] === "function") {
      this.callbackSet[uuid](data)
    }
    if (methodName === this.buildMethod($ipcConstants.taskStateUpdate, "response")) {
      this.handleTaskStateUpdate(event.data as CompressTask)
    }
  }

  handleTaskStateUpdate(task: CompressTask) {
    console.error("handleTaskStateUpdate", task)
    const taskList = [...useAppStore.getState().tasks]
    let taskIdx = taskList.findIndex(e => e.id === task.id)
    if (taskIdx >= 0) {
      taskList.splice(taskIdx, 1, {...task})
      useAppStore.setState({tasks: taskList})
    }
  }

  registerTask(files: File[]): Observable<undefined> {
    console.log(`files`, files)
    const newTasks: CompressTask[] = files.map(e => {
      const uuid = $helper.uuid()
      this.cacheFileSet[uuid] = e
      return {
        id: uuid,
        path: e.path,
        size: e.size,
        type: e.type,
        name: e.name,
        state: 0,
        progress: {upload: 0, download: 0},
        saveOptions: {...useSettingStore.getState()}
      }
    })
    useAppStore.setState({tasks: [...useAppStore.getState().tasks, ...newTasks]})
    return this.trigger<undefined>({
      methodName: this.buildMethod($ipcConstants.registerTask),
      data: [...newTasks]
    })
  }

  reloadFailedTask(): Observable<undefined> {
    const tasks = [...useAppStore.getState().tasks]
    let newTasks = tasks.filter(e => e.state === 5).map(item => {
      return {...item, state: 0, progress: {upload: 0, download: 0}}
    })
    newTasks.forEach(item => {
      const idx = tasks.findIndex(e => e.id === item.id)
      tasks.splice(idx, 1, item)
    })
    useAppStore.setState({tasks})
    return this.trigger<undefined>({
      methodName: this.buildMethod($ipcConstants.registerTask),
      data: [...newTasks]
    })
  }

  exitApp() {
    return this.trigger({
      methodName: this.buildMethod($ipcConstants.exitApp)
    })
  }

  openSaveDir(): Observable<string> {
    return this.trigger<string>({
      methodName: this.buildMethod($ipcConstants.openSaveDir),
      data: useSettingStore.getState().saveDir || useSettingStore.getState().systemDownloadDir
    })
  }

  getSystemDownloadDir() {
    this.trigger<string>({
      methodName: this.buildMethod($ipcConstants.getSystemDownloadDir),
    }).subscribe(
      res => {
        useSettingStore.setState({systemDownloadDir: res})
      }
    )
  }

  openDictSelector(): Observable<{canceled: boolean, filePaths: string[]}> {
    return this.trigger({
      methodName: this.buildMethod($ipcConstants.openFolderSelector),
    })
  }

  trigger<T>(payload: {methodName: string, data?: any, callback?: Function}): Observable<T> {
    return new Observable<T>(obs => {
      const uuid: string = $helper.uuid(30, "ipc")
      this.callbackSet[uuid] = (result: T) => {
        obs.next(result)
        obs.complete()
      }
      ipcRenderer.send($ipcConstants.ipcMessageId, {
        methodName: payload.methodName,
        uuid,
        data: payload.data || {}
      })
    })
    
  }

  buildMethod(methodName: string, suffix?: "request" | "response"): string {
    return `${methodName}.${suffix || "request"}`
  }
}

const $ipc = new IpcService()
export default $ipc


